package com.common.print;

import org.jetbrains.annotations.NotNull;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @ClassName AQSDemo
 * @Description TODO
 * @Author admin
 * @Date 2021/4/28 14:26
 * @Version 1.0
 **/
public class AQSDemo implements Lock {

    @Override
    public void lock() {
        // 该方法会调用重写的tryAcquire 如果没有获取到锁会将线程放到队列尾部
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @NotNull
    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    /**
     * @Description: 自定义同步器
     * @Author: liuhuanjin
     * @Date: 2021/4/28 14:44
     * @return: null
     **/
    static class Sync extends AbstractQueuedSynchronizer {
        /**
         * @Description: 尝试获取资源
         * @Author: liuhuanjin
         * @Date: 2021/4/28 14:31
         * @param arg:
         * @return: boolean
         **/
        @Override
        protected boolean tryAcquire(int arg) {
            // 利用cas设置state 成功则将当前线程设置为独占
            if(compareAndSetState(0,1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /**
         * @Description: 释放资源
         * @Author: liuhuanjin
         * @Date: 2021/4/28 14:34
         * @param arg:
         * @return: boolean
         **/
        @Override
        protected boolean tryRelease(int arg) {
            if(getState() == 0){
                // 没有独占资源 无需释放
                throw new IllegalMonitorStateException();
            }
            // 将独占线程设置为null
            setExclusiveOwnerThread(null);
            // 状态设置为0
            setState(0);
            return true;
        }

        /**
         * @Description: 判断当前线程是否被独占
         * @Author: liuhuanjin
         * @Date: 2021/4/28 14:30
         * @return: boolean
         **/
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        Condition newCondition() {
            return new ConditionObject();
        }
    }

    static Sync sync = new Sync();

    private static Integer num = 1;
    public static void main(String[] args) {

        AQSDemo lock = new AQSDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3;) {
                    try {
                        lock.lock();
                        while (num == 1){
                            System.out.println("A");
                            num = 2;
                            i++;
                        }
                    }finally {
                        lock.unlock();
                    }
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3;) {
                    try {
                        lock.lock();
                        while (num == 2){
                            System.out.println("B");
                            num = 3;
                            i++;
                        }
                    }finally {
                        lock.unlock();
                    }
                }
            }
        });

        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3;) {
                    try {
                        lock.lock();
                        while (num == 3){
                            System.out.println("C");
                            num = 1;
                            i++;
                        }
                    }finally {
                        lock.unlock();
                    }
                }
            }
        });

        threadA.start();
        threadB.start();
        threadC.start();

    }

}
